#include <linux/module.h>
#include <linux/kernel.h>       /**< printk() */
#include <linux/init.h>

#include <linux/slab.h>
#include <linux/types.h>        /**< size_t */
#include <linux/errno.h>        /**< error codes */
#include <linux/string.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#include <linux/miscdevice.h>
#include <linux/of.h>
#include <linux/of_device.h>

#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/pm.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/interrupt.h>


#define DEV_NAME         "gpio_key"


int dev_registers[25];
int gpiohao = 0;//gpio号
int isd=0;
int gpio_fhz = 0;//gpio返回值
//int g_irq = 0;
int err = 0;
int irq_num = 0;
static struct input_dev *button_dev; 

//工作队列
struct work_struct sunday_wq; //定义工作队列和关联函数
void sunday_do_work(struct work_struct *work);

int hello_open(struct inode* inode, struct file *filp)
{
    filp->private_data = dev_registers;
    return 0;
}

int hello_release(struct inode* inode, struct file* filp)
{
	return 0;
}
//文件读取函数
static ssize_t hello_read(struct file* filp, char __user* buf, size_t size, loff_t* ppos)
{	 
    //int ret = 0;  
    return 0;
}

//文件写入函数
static ssize_t hello_write(struct file* filp, const char __user* buf, size_t size, loff_t* ppos)
{
    //int ret = 0;
    return 0;
}

//文件操作集合
struct file_operations hello_fops = {
	.owner = THIS_MODULE,
	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
};

struct  miscdevice miscdev = {
	.minor = 255,   
	.name = "hello",
	.fops = &hello_fops,
};

//中断处理底半部
void sunday_do_work(struct work_struct *work)
    {
     printk("interrupt of sunday!\n");
    }
//中断处理顶半部
static irqreturn_t sunday_interrupt(int irq,void *dev_id)
    {
    schedule_work(&sunday_wq);//调度工作队列执行
    return IRQ_HANDLED;
    }

static int sunday_probe(struct platform_device *dev)
{
    int ret = 0;
    //int irq = -1;
    unsigned long irqflags;
    struct device_node* np = dev->dev.of_node;
    misc_register(&miscdev);//注册杂项设备

    if(np == NULL)
    {
        pr_info("of_node is NULL\n");
        return 0;
    }
    
    gpiohao = of_get_named_gpio(np,"gpios",0);//获得GPIO端口号
    if (gpiohao < 0) {
  		printk("of_get_named_gpio error \n");
  		return -1;
  	}
    printk("of_get_named_gpio OK\n");
    
    gpio_fhz = gpio_request(gpiohao,"gpios");   //申请使用GPIO号
	if (gpio_fhz < 0) {
  		printk("gpio_request error \n");
  		return -1;
  	}
    printk("gpio_request OK\n");
    //申请gpio中断号
    //g_irq = (irq = gpio_to_irq(gpiohao));
    irq_num = gpio_to_irq(gpiohao);//通过gpio号获取中断号
  	if (irq_num < 0) {
  		printk("irq_num error \n");
  		return -1;
  	}
    printk("irq_num OK \n");
    printk("irq_num = %d\n",irq_num);
    
    irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;//中断类型（工作队列）
    
    if(request_irq(irq_num,sunday_interrupt,irqflags,DEV_NAME,NULL))
    {
    printk(KERN_ERR"cannotallocate irq");
    }
    printk("request_irq OK!\n");//申请中断

    INIT_WORK(&sunday_wq,sunday_do_work); //初始化工作队列

    button_dev = input_allocate_device();//分配input_dev
    if(button_dev == NULL)
    { 
          printk(KERN_ERR "notenough memory\n");
          err= - ENOMEM;
    }

     /*设置输入设备支持的事件类型和事件代码 */
     button_dev->name = "key_gpio";
     set_bit(EV_KEY, button_dev->evbit);
     set_bit(KEY_1, button_dev->keybit);

   /*设置输入设备支持的事件类型和事件代码 */ 
    err = input_register_device(button_dev);
    if(err) {
          printk(KERN_ERR "failedto register device\n");
          input_free_device(button_dev);
	   }    

    return ret;
}

static int sunday_remove(struct platform_device *dev)   //设备节点驱动退出函数
{
    printk(KERN_NOTICE "remove...\n");
    return 0;
}

static struct of_device_id sunday_of_match[] = {
	{ .compatible = "ts,irq", },   //匹配设备名
	{ /* sentinel */ }
};

static struct platform_driver sunday_driver = {
	.driver = {
		.name = "myirq",
		.of_match_table = of_match_ptr(sunday_of_match),   //把文件名转换成字符串
	},
	.probe  = sunday_probe,
    .remove = sunday_remove,  //退出，移除设备模块
};


 
//驱动加载函数
static int hello_init(void){
	
    int ret = 0;
    ret = platform_driver_register(&sunday_driver);//注册设备
    if (ret)
    {
        pr_info("sunday platform_driver_register failed!\n");
        return ret;
    }
    
    pr_info("platform_driver_register Init OK!\n");

    return ret;
}


//驱动卸载函数
static void hello_exit(void){
    platform_driver_unregister(&sunday_driver);//设备注销函数
    misc_deregister(&miscdev);
    gpio_free(gpiohao);
    //释放中断
    free_irq(irq_num,NULL);//释放中断
};

module_init(hello_init);
module_exit(hello_exit);


    
